import {
    Fog,
    Group,
    MeshBasicMaterial,
    DirectionalLight,
    AmbientLight,
    PointLight,
    Vector3,
    MeshLambertMaterial,
    LineBasicMaterial,
    Color,
    MeshStandardMaterial,
    PlaneGeometry,
    Mesh,
    DoubleSide,
    RepeatWrapping,
    SRGBColorSpace,
    AdditiveBlending,
    VideoTexture,
    NearestFilter,
    BoxGeometry,
    TubeGeometry,
    QuadraticBezierCurve3,
    PointsMaterial,
    Sprite,
    SpriteMaterial,
} from "three";
import {
    Mini3d,
    Grid,
    Label3d,
    Plane,
    Particles,
    GradientShader, Sizes,
} from "../mini3d";
import {Assets} from "./map-gd/assets";
import {ExtrudeMap} from "./map-gd/extrudeMap";
import {BaseMap} from "./map-gd/baseMap";
import {Line} from "./map-gd/line";
import {geoMercator} from "d3-geo";

import scatterData from "./map-gd/scatter";
import infoData from "./map-gd/infoData";
import gsap from "gsap";
import {InteractionManager} from "three.interactive";
import {StaticGroup} from "../model";
import {MapSetting} from "./map-gd/mapSetting";

function sortByValue(data) {
    data.sort((a, b) => b.value - a.value);
    return data;
}

export class World extends Mini3d {
    pointCenter: any;
    flyLineCenter: any;
    depth: any;
    clicked: any;
    interactionManager: any;
    playing: any;
    assets: any;
    labelGroup: any;
    label3d: any;
    eventElement: any;
    defaultMaterial: any;
    defaultLightMaterial: any;
    focusMapGroup: any;
    focusMapTopMaterial: any;
    focusMapSideMaterial: any;
    otherLabel: any;
    areaInfoLineMaterial: any;
    rotateBorder1: any;
    allBar: any;
    rotateBorder2: any;
    allProvinceLabel: any;
    allBarMaterial: any;
    flyLineGroup: any;
    quanGroup: any;
    instance: any;
    scatterGroup: any;
    infoPointIndex: any;
    infoLabelElement: any;
    infoPointLabelTime: any;
    labelIcon = "3dmap/assets/texture/label-icon.png";
    InfoPointGroup: any;
    flyLineFocusGroup: any;
    particles: any;
    allGuangquan: any;

    /**
     * 存储需要删除的元素
     */
    mapGroup: any;
    barGroup: any;


    constructor(canvas) {
        super(canvas);
        // 中心坐标
        this.pointCenter = StaticGroup.areaInfo.centroid;
        this.flyLineCenter = StaticGroup.areaInfo.centroid;
        this.depth = 0.5;
        this.clicked = false;
        this.scene.fog = new Fog(StaticGroup.options.base_scene_bg, 1, 50);
        this.scene.background = new Color(StaticGroup.options.base_scene_bg);
        // 相机初始位置
        this.camera.instance.position.set(
            -13.767695123014105,
            12.990152163077308,
            39.28228164159694
        );
        this.camera.instance.near = 1;
        this.camera.instance.far = 10000;
        this.camera.instance.updateProjectionMatrix();
        // 创建交互管理
        this.interactionManager = new InteractionManager(
            this.renderer.instance,
            this.camera.instance,
            this.canvas
        );
        // 播放状态
        this.playing = false;
        // 创建环境光
        this.initEnvironment();
        this.assets = new Assets(() => {
            this.labelGroup = new Group();
            this.label3d = new Label3d(this);
            this.labelGroup.rotateX(-Math.PI / 2);
            this.scene.add(this.labelGroup);
            // 事件元素
            this.eventElement = [];
            // 鼠标移上移除的材质
            this.defaultMaterial = null; // 默认材质
            this.defaultLightMaterial = null; // 高亮材质
            // 创建底部高亮
           //this.createFloor();
            // 模糊边线
            this.createChinaBlurLine();
            // 扩散网格
            this.createGrid();
            // 旋转圆环
            this.createRotateBorder();
            // 创建标签
            this.createLabel();
            // 创建地图
            this.createMap();

            this.createEvent();
            // 创建飞线
            this.createFlyLine();

            // 创建粒子
            this.createParticles();
            // 创建散点图
            this.createScatter();
            // 创建信息点
            this.createInfoPoint();
            // 创建动画时间线
            this.initLoadTime();
        });
    }

    /**
     * 加载动画时间线
     */
    initLoadTime() {
        const tl = gsap.timeline();
        //渐进动画
        tl.add(
            gsap.to(this.camera.instance.position, {
                duration: 2.5,
                x: -0.2515849818960619,
                y: 12.397744557047988,
                z: 14.647659671139275,
                ease: "circ.out",
            })
        );

        //地图位置动画
        tl.add(
            gsap.to(this.focusMapGroup.position, {
                duration: 1,
                x: 0,
                y: 0,
                z: 0,
            }),
            "focusMap"
        );
        //地图位置动画
        tl.add(
            gsap.to(this.focusMapGroup.scale, {
                duration: 1,
                x: 1,
                y: 1,
                z: 1,
                ease: "circ.out",
            }),
            "focusMap"
        );
        //顶部材质
        tl.add(
            gsap.to(this.focusMapTopMaterial, {
                duration: 1,
                opacity: 1,
                ease: "circ.out",
            }),
            "focusMapOpacity"
        );
        //侧面材质
        tl.add(
            gsap.to(this.focusMapSideMaterial, {
                duration: 1,
                opacity: 1,
                ease: "circ.out",
                onComplete: () => {
                    this.focusMapSideMaterial.transparent = false;
                },
            }),
            "focusMapOpacity"
        );
        //加载其他标签
        this.otherLabel.map((item, index) => {
            let element = item.element.querySelector(".other-label");
            tl.add(
                gsap.to(element, {
                    duration: 1,
                    delay: 0.1 * index,
                    translateY: 0,
                    opacity: 1,
                    ease: "circ.out",
                }),
                "focusMapOpacity"
            );
        });
        //区域信息线材质
        tl.add(
            gsap.to(this.areaInfoLineMaterial, {
                duration: 0.5,
                delay: 0.3,
                opacity: 1,
            }),
            "focusMapOpacity"
        );
        //旋转光圈1
        tl.add(
            gsap.to(this.rotateBorder1.scale, {
                delay: 0.3,
                duration: 1,
                x: 1,
                y: 1,
                z: 1,
                ease: "circ.out",
            }),
            "focusMapOpacity"
        );
        //旋转光圈1
        tl.add(
            gsap.to(this.rotateBorder2.scale, {
                duration: 1,
                delay: 0.5,
                x: 1,
                y: 1,
                z: 1,
                ease: "circ.out",
            }),
            "focusMapOpacity"
        );
        //加载柱子标签
        if (this.allBar){
            tl.add(() => {
                this.initBarTime();
            })
        }


    }

    /**
     * 加载柱状图,标签
     */
    initBarTime() {
        const tl = gsap.timeline();
        //柱子动画
        this.allBar.map((item, index) => {
            tl.add(
                gsap.to(item.scale, {
                    duration: 1,
                    delay: 0.1 * index,
                    x: 1,
                    y: 1,
                    z: 1,
                    ease: "circ.out",
                }),
                "bar"
            );
        });
        //加载柱子材质
        this.allBarMaterial.map((item, index) => {
            tl.add(
                gsap.to(item, {
                    duration: 1,
                    delay: 0.1 * index,
                    opacity: 1,
                    ease: "circ.out",
                }),
                "bar"
            );
        });
        //加载柱子光圈
        this.allGuangquan.map((item, index) => {
            tl.add(
                gsap.to(item.children[0].scale, {
                    duration: 1,
                    delay: 0.1 * index,
                    x: 1,
                    y: 1,
                    z: 1,
                    ease: "circ.out",
                }),
                "bar"
            );
            tl.add(
                gsap.to(item.children[1].scale, {
                    duration: 1,
                    delay: 0.1 * index,
                    x: 1,
                    y: 1,
                    z: 1,
                    ease: "circ.out",
                }),
                "bar"
            );
        });

        //省份标签
        this.allProvinceLabel.map((item, index) => {
            let element = item.element.querySelector(".provinces-label-wrap");
            let number = item.element.querySelector(".number .value");
            let numberVal = Number(number.innerText);
            let numberAnimate = {
                score: 0,
            };
            tl.add(
                gsap.to(element, {
                    duration: 1,
                    delay: 0.2 * index,
                    translateY: 0,
                    opacity: 1,
                    ease: "circ.out",
                }),
                "bar"
            );
            let text = gsap.to(numberAnimate, {
                duration: 1,
                delay: 0.2 * index,
                score: numberVal,
                onUpdate: showScore,
            });

            function showScore() {
                number.innerText = numberAnimate.score.toFixed(0);
            }

            tl.add(text, "bar");
            StaticGroup.isSuccess = true;
        });
    }

    /**
     * 删除柱子
     */
    reloadBar() {
        const tl = gsap.timeline();
        tl.add(() => {
            if (this.barGroup && this.allBar) {
                this.allBar.map((item, index) => {
                    gsap.to(item, {
                        duration: 0.5,
                        delay: 0.5,
                        visible: false,
                        ease: "circ.out",
                    });
                });
                this.allBarMaterial.map((item, index) => {
                    gsap.to(item, {
                        duration: 0.5,
                        delay: 0.5,
                        opacity: 0,
                        ease: "circ.out",
                    })
                });
            }
        })
        tl.add(() => {
            this.scene.remove(this.barGroup);
            this.barGroup = null;
            this.allBar = null;
        })


        //删除光圈
        if (this.quanGroup) {
            //底部光圈
            this.allGuangquan.map((item, index) => {
                tl.add(() => {
                    gsap.to(item.children[0], {
                        duration: 0.5,
                        delay: 0.5,
                        visible: false,
                        ease: "circ.out",
                    })
                })
                tl.add(() => {
                    gsap.to(item.children[1], {
                        duration: 0.5,
                        delay: 0.5,
                        visible: false,
                        ease: "circ.out",
                    })
                })
            });
        }
        tl.add(() => {
            this.scene.remove(this.quanGroup);
            this.quanGroup = null;
            this.allGuangquan = null;
        });


        //柱子标签
        this.allProvinceLabel.map((item, index) => {
            let element = item.element.querySelector(".provinces-label-wrap");
            let number = item.element.querySelector(".number .value");
            tl.add(() => {
                gsap.to(element, {
                    duration: 0.5,
                    delay: 0.5,
                    opacity: 0,
                    ease: "circ.out",
                })
            });
            tl.add(() => {
                gsap.to(number, {
                    duration: 0.5,
                    delay: 0.5,
                    opacity: 0,
                    ease: "circ.out",
                })
            });
        });

        tl.add(() => {
            this.createBar();
        })
        //加载数据动画
        tl.add(() => {
            this.initBarTime();
        })
    }

    initEnvironment() {
        const sun = new AmbientLight(StaticGroup.options.base_am_light, 3);
        sun.uuid='base_am_light';
        this.scene.add(sun);
        // 方向光
        const directionalLight = new DirectionalLight(StaticGroup.options.base_direc_light, 8);
        directionalLight.position.set(-30, 6, -8);
        directionalLight.castShadow = true;
        directionalLight.shadow.radius = 20;
        directionalLight.shadow.mapSize.width = 1024;
        directionalLight.shadow.mapSize.height = 1024;
        directionalLight.uuid='base_direc_light'
        this.scene.add(directionalLight);

        this.createPointLight({
            color: StaticGroup.options.base_pointLight_1,
            intensity: 600,
            distance: 10000,
            x: -9,
            y: 3,
            z: -3,
        },'base_pointLight_1');

        // this.createPointLight({
        //     color: StaticGroup.options.base_pointLight_1,
        //     intensity: 230,
        //     distance: 10000,
        //     x: 0,
        //     y: 2,
        //     z: 5,
        // },'base_pointLight_2');
    }

    createPointLight(pointParams,uuid) {
        const pointLight = new PointLight(
            pointParams.color,
            pointParams.intensity,
            pointParams.distance
        );
        pointLight.position.set(pointParams.x, pointParams.y, pointParams.z);
        pointLight.uuid=uuid;
        this.scene.add(pointLight);
    }

    // 模型渲染
    createMap() {
        this.mapGroup = new Group();
        let focusMapGroup = new Group();
        this.focusMapGroup = focusMapGroup;
        let {china, chinaTopLine, chinaBottomLine} = this.createChina();
        let {areaInfo, areaInfoTop, areaInfoLine} = this.createProvince();
        china.mapGroup.uuid = 'china';
        china.mapGroup.name = 'china';
        chinaTopLine.lineGroup.uuid = 'chinaTopLine';
        chinaTopLine.lineGroup.name = 'chinaTopLine';

        chinaBottomLine.lineGroup.uuid = 'chinaBottomLine';
        chinaBottomLine.lineGroup.name = 'chinaBottomLine';

        china.setParent(this.mapGroup);
        chinaTopLine.setParent(this.mapGroup);

        chinaBottomLine.setParent(this.mapGroup);


        areaInfoTop.mapGroup.uuid = 'areaInfoTop';
        areaInfoTop.mapGroup.name = 'areaInfoTop';

        areaInfoLine.lineGroup.uuid = 'areaInfoLine';
        areaInfoLine.lineGroup.name = 'areaInfoLine';

        areaInfo.setParent(focusMapGroup);
        areaInfoTop.setParent(focusMapGroup);
        areaInfoLine.setParent(focusMapGroup);
        focusMapGroup.position.set(0, 0, -0.01);
        focusMapGroup.scale.set(1, 1, 0);
        this.mapGroup.add(focusMapGroup);
        this.mapGroup.rotateX(-Math.PI / 2);
        this.mapGroup.position.set(0, 0.2, 0);

        this.mapGroup.uuid = 'mapGroup'
        this.scene.add(this.mapGroup);
        this.createBar();
    }

    createChina() {
        let chinaData = this.assets.instance.getResource("china");
        let china = new BaseMap(this, {
            data: chinaData,
            center: this.pointCenter,
            merge: false,
            material: new MeshLambertMaterial({
                color: StaticGroup.options.base_area_color,
                transparent: true,
                opacity: 1,
            }),

            renderOrder: 2,
        });

        let chinaTopLine = new Line(this, {
            center: this.pointCenter,
            visibelProvince: StaticGroup.adcode, // 隐藏区域的界线
            data: chinaData,
            material: new LineBasicMaterial({color: StaticGroup.options.base_bg_line_color}),
            renderOrder: 3,
        });

        chinaTopLine.lineGroup.position.z += 0.01;

        let chinaBottomLine = new Line(this, {
            center: this.pointCenter,
            data: chinaData,
            material: new LineBasicMaterial({
                color: StaticGroup.options.base_china_top_Line,
                transparent: true,
                opacity: 1,
            }),
            renderOrder: 3,
        });

        chinaBottomLine.lineGroup.position.z -= 0.59;

        return {china, chinaTopLine, chinaBottomLine};
    }

    createProvince() {
        let areaInfoData = this.assets.instance.getResource("areaInfo");
        let [topMaterial, sideMaterial] = this.createProvinceMaterial();
        this.focusMapTopMaterial = topMaterial;
        this.focusMapSideMaterial = sideMaterial;
        let areaInfo = new ExtrudeMap(this, {
            center: this.pointCenter,
            position: new Vector3(0, 0, 0.11),
            data: areaInfoData,
            depth: StaticGroup.areaConfig.depth,
            topFaceMaterial: topMaterial,

            sideMaterial: sideMaterial,
            renderOrder: 9,
        });

        let faceMaterial = new MeshStandardMaterial({
            color: "#ffffff",
            transparent: true,
            opacity: 0.5,
        });

        new GradientShader(faceMaterial, { uColor1: 0x2a6e92, uColor2: 0x102736 });
        // 设置默认材质
        this.defaultMaterial = faceMaterial;
        this.defaultLightMaterial = this.defaultMaterial.clone();
        this.defaultLightMaterial.emissive.setHex('#0b112d');
        this.defaultLightMaterial.emissiveIntensity = 3.5;
        let areaInfoTop = new BaseMap(this, {
            center: this.pointCenter,
            position: new Vector3(0, 0, StaticGroup.areaConfig.depth+0.22),
            data: areaInfoData,
            material: faceMaterial,
            renderOrder: 2,
        });
        areaInfoTop.mapGroup.children.map((group) => {
            group.children.map((mesh) => {
                if (mesh.type === "Mesh") {
                    this.eventElement.push(mesh);
                }
            });
        });
        // 地图线
        this.areaInfoLineMaterial = new LineBasicMaterial({
            color: StaticGroup.options.base_area_line_color,
            opacity: 0,
            transparent: true,
            fog: false,
        });
        let areaInfoLine = new Line(this, {
            center: this.pointCenter,
            data: areaInfoData,
            material: this.areaInfoLineMaterial,
            renderOrder: 3,
        });

        areaInfoLine.lineGroup.position.z = StaticGroup.areaConfig.depth+0.23;

        return {
            areaInfo,
            areaInfoTop,
            areaInfoLine,
        };
    }

    /**
     * 创建省份边线
     */
    createProvinceMaterial() {
        let topMaterial = new MeshLambertMaterial({
            color: 0xffffff,
            transparent: true,
            opacity: 0,
            fog: false,
            side: DoubleSide,
        });
        topMaterial.onBeforeCompile = (shader) => {
            shader.uniforms = {
                ...shader.uniforms,
                uColor1: { value: new Color('#2a6e92') }, // 419daa
                uColor2: { value: new Color('#102736') },
            };
            shader.vertexShader = shader.vertexShader.replace(
                "void main() {",
                `
        attribute float alpha;
        varying vec3 vPosition;
        varying float vAlpha;
        void main() {
          vAlpha = alpha;
          vPosition = position;
      `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "void main() {",
                `
        varying vec3 vPosition;
        varying float vAlpha;
        uniform vec3 uColor1;
        uniform vec3 uColor2;
      
        void main() {
      `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "#include <opaque_fragment>",
                /* glsl */ `
      #ifdef OPAQUE
      diffuseColor.a = 1.0;
      #endif
      
      // https://github.com/mrdoob/three.js/pull/22425
      #ifdef USE_TRANSMISSION
      diffuseColor.a *= transmissionAlpha + 0.1;
      #endif
      vec3 gradient = mix(uColor1, uColor2, vPosition.x/15.78); // 15.78
      
      outgoingLight = outgoingLight*gradient;
      float topAlpha = 0.5;
      if(vPosition.z>0.3){
        diffuseColor.a *= topAlpha;
      }
      
      gl_FragColor = vec4( outgoingLight, diffuseColor.a  );
      `
            );
        };
        let sideMap = this.assets.instance.getResource("side");
        sideMap.wrapS = RepeatWrapping;
        sideMap.wrapT = RepeatWrapping;
        sideMap.repeat.set(1, 1.5);
        sideMap.offset.y += 0.065;
        let sideMaterial = new MeshStandardMaterial({
            color: 0xffffff,
            map: sideMap,
            fog: false,

            opacity: 0,
            side: DoubleSide,
        });

        this.time.on("tick", () => {
            sideMap.offset.y += 0.005;
        });
        sideMaterial.onBeforeCompile = (shader) => {
            shader.uniforms = {
                ...shader.uniforms,
                uColor1: { value: new Color(0x2a6e92) },
                uColor2: { value: new Color(0x2a6e92) },
            };
            shader.vertexShader = shader.vertexShader.replace(
                "void main() {",
                `
        attribute float alpha;
        varying vec3 vPosition;
        varying float vAlpha;
        void main() {
          vAlpha = alpha;
          vPosition = position;
      `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "void main() {",
                `
        varying vec3 vPosition;
        varying float vAlpha;
        uniform vec3 uColor1;
        uniform vec3 uColor2;
      
        void main() {
      `
            );
            shader.fragmentShader = shader.fragmentShader.replace(
                "#include <opaque_fragment>",
                /* glsl */ `
      #ifdef OPAQUE
      diffuseColor.a = 1.0;
      #endif
      
      // https://github.com/mrdoob/three.js/pull/22425
      #ifdef USE_TRANSMISSION
      diffuseColor.a *= transmissionAlpha + 0.1;
      #endif
      vec3 gradient = mix(uColor1, uColor2, vPosition.z/1.2);
      
      outgoingLight = outgoingLight*gradient;
      
      
      gl_FragColor = vec4( outgoingLight, diffuseColor.a  );
      `
            );
        };
        return [topMaterial, sideMaterial];
    }

    // 创建柱状图
    createBar() {
        let self = this;
        let num=StaticGroup.bindPointData.length;
        if (StaticGroup.options.data_num_show){
            num=StaticGroup.options.data_num;
        }
        let data = sortByValue(StaticGroup.bindPointData).filter((item, index) => index < num);
        this.barGroup = new Group();
        const factor = 0.7;
        const height = 4.0 * factor;

        this.allBar = [];
        this.allBarMaterial = [];
        this.allGuangquan = [];
        this.allProvinceLabel = [];
        this.scene.add(this.barGroup);
        if (data.length==0){
            return;
        }
        const max = data[0].value;
        data.map((item, index) => {
            let geoHeight = height * (item.value / max);

            let material = new MeshBasicMaterial({
                color: 0xffffff,
                transparent: true,
                opacity: 0,
                depthTest: false,
                fog: false,
            });

            new GradientShader(material, {
                uColor1: index > 3 ? 0xfbdf88 : 0x50bbfe,
                uColor2: index > 3 ? 0xfffef4 : 0x77fbf5,
                size: geoHeight,
                dir: "y",
            });
            const geo = new BoxGeometry(0.1 * factor, 0.1 * factor, geoHeight);

            geo.translate(0, 0, geoHeight / 2);
            const mesh = new Mesh(geo, material);
            mesh.renderOrder = 5;
            mesh.name='bar';
            mesh.userData=item;
            this.eventElement.push(mesh);
            let areaBar = mesh;
            let [x, y] = this.geoProjection(item.centroid);
            areaBar.position.set(x, -y, item.show?0.95:0.45);
            areaBar.scale.set(1, 1, 0);
            let guangQuan = this.createQuan(new Vector3(x, item.show?0.94:0.44, y), index);
            let hg = this.createHUIGUANG(geoHeight, index > 3 ? 0xfffef4 : 0x77fbf5);
            areaBar.add(...hg);
            this.barGroup.add(areaBar);
            this.barGroup.rotation.x = -Math.PI / 2;
            let barLabel = labelStyle04(
                item,
                index,
                new Vector3(x, -y, 1.2 + geoHeight)
            );
            this.allBar.push(areaBar);
            this.allBarMaterial.push(material);
            this.allGuangquan.push(guangQuan);
            this.allProvinceLabel.push(barLabel);
        });
        function labelStyle04(data, index, position) {
            let label = self.label3d.create("", "provinces-label", true);

            label.init(
                `<div class="provinces-label ${index > 4 ? "yellow" : ""}">
      <div class="provinces-label-wrap" style="background: ${StaticGroup.options.bar_label_bg};border-radius: ${StaticGroup.options.bar_label_pos.left}px ${StaticGroup.options.bar_label_pos.top}px ${StaticGroup.options.bar_label_pos.right}px ${StaticGroup.options.bar_label_pos.bottom}px">
        <div class="no" style="color: ${StaticGroup.options.bar_no_textStyle.color};font-family: '${StaticGroup.options.bar_no_textStyle.fontFamily}';font-size: ${StaticGroup.options.bar_no_textStyle.fontSize};font-style: ${StaticGroup.options.bar_no_textStyle.fontStyle};font-weight: '${StaticGroup.options.bar_no_textStyle.fontWeight}'">
            ${index + 1}
        </div>
        <div class="name">
          <span class="zh" style="color: ${StaticGroup.options.bar_name_textStyle.color};font-family: '${StaticGroup.options.bar_name_textStyle.fontFamily}';font-size: ${StaticGroup.options.bar_name_textStyle.fontSize};font-style: ${StaticGroup.options.bar_name_textStyle.fontStyle};font-weight: '${StaticGroup.options.bar_name_textStyle.fontWeight}'">${data.name}</span>
        </div>
        <div class="number">
        <span class="value" style="color: ${StaticGroup.options.bar_num_textStyle.color};font-family: '${StaticGroup.options.bar_num_textStyle.fontFamily}';font-size: ${StaticGroup.options.bar_num_textStyle.fontSize};font-style: ${StaticGroup.options.bar_num_textStyle.fontStyle};font-weight: '${StaticGroup.options.bar_num_textStyle.fontWeight}'">
            ${data.value}
        </span>
        <span class="unit" style=color: ${StaticGroup.options.bar_unit_textStyle.color};font-family: '${StaticGroup.options.bar_unit_textStyle.fontFamily}';font-size: ${StaticGroup.options.bar_unit_textStyle.fontSize};font-style: ${StaticGroup.options.bar_unit_textStyle.fontStyle};font-weight: '${StaticGroup.options.bar_unit_textStyle.fontWeight}'">
            ${data.unit?data.unit:'万'}
        </span></div>
      </div>
    </div>`,
                position
            );
            self.label3d.setLabelStyle(label, 0.01, "x");
            label.setParent(self.labelGroup);
            return label;
        }
    }

    // 添加事件
    createEvent() {
        // hover的对象
        let objectsHover = [] as any;
        // 重置
        const reset = (mesh) => {
            // 还原颜色
            mesh.traverse((obj) => {
                if (obj.isMesh) {
                    obj.material = this.defaultMaterial;
                }
            });
        };
        const move = (mesh) => {
            // 设置发光颜色
            mesh.traverse((obj) => {
                if (obj.isMesh) {
                    obj.material = this.defaultLightMaterial;
                }
            });
        };
        //
        // 循环添加事件
        this.eventElement.map((mesh) => {
            this.interactionManager.add(mesh);

            if (mesh.name == 'bar') {
                mesh.addEventListener("mousedown", (ev) => {
                    this.clickHandler(ev.target.userData.name)
                });
            }
            mesh.addEventListener("mouseover", (event) => {
                if (mesh.name != 'bar') {
                    if (!objectsHover.includes(event.target.parent)) {
                        objectsHover.push(event.target.parent);
                    }
                    move(event.target.parent);
                }
                document.body.style.cursor = "pointer";
            });
            mesh.addEventListener("mouseout", (event) => {
                if (mesh.name != 'bar') {
                    objectsHover = objectsHover.filter(
                        (n) => n.userData.name !== event.target.parent.userData.name
                    );
                    if (objectsHover.length > 0) {
                        const mesh = objectsHover[objectsHover.length - 1];
                    }
                    reset(event.target.parent);
                }
                document.body.style.cursor = "default";
            });
        });
    }

    createHUIGUANG(h, color) {
        let geometry = new PlaneGeometry(0.35, h);
        geometry.translate(0, h / 2, 0);
        const texture = this.assets.instance.getResource("huiguang");
        texture.colorSpace = SRGBColorSpace;
        texture.wrapS = RepeatWrapping;
        texture.wrapT = RepeatWrapping;
        let material = new MeshBasicMaterial({
            color: color,
            map: texture,
            transparent: true,
            opacity: 0.4,
            depthWrite: false,

            side: DoubleSide,
            blending: AdditiveBlending,
        });
        let mesh = new Mesh(geometry, material);
        mesh.renderOrder = 10;
        mesh.rotateX(Math.PI / 2);
        let mesh2 = mesh.clone();
        let mesh3 = mesh.clone();
        mesh2.rotateY((Math.PI / 180) * 60);
        mesh3.rotateY((Math.PI / 180) * 120);
        return [mesh, mesh2, mesh3];
    }

    createQuan(position, index) {
        const guangquan1 = this.assets.instance.getResource("guangquan1");
        const guangquan2 = this.assets.instance.getResource("guangquan2");
        let geometry = new PlaneGeometry(0.5, 0.5);

        let material1 = new MeshBasicMaterial({
            color: 0xffffff,
            map: guangquan1,
            alphaMap: guangquan1,
            opacity: 1,
            transparent: true,
            depthTest: false,
            fog: false,
            blending: AdditiveBlending,
        });
        let material2 = new MeshBasicMaterial({
            color: 0xffffff,
            map: guangquan2,
            alphaMap: guangquan2,
            opacity: 1,
            transparent: true,
            depthTest: false,
            fog: false,
            blending: AdditiveBlending,
        });
        let mesh1 = new Mesh(geometry, material1);
        let mesh2 = new Mesh(geometry, material2);
        mesh1.renderOrder = 6;
        mesh2.renderOrder = 6;
        mesh1.rotateX(-Math.PI / 2);
        mesh2.rotateX(-Math.PI / 2);
        mesh1.position.copy(position);
        mesh2.position.copy(position);
        mesh2.position.y -= 0.001;
        mesh1.scale.set(0, 0, 0);
        mesh2.scale.set(0, 0, 0);
        this.quanGroup = new Group();
        this.quanGroup.add(mesh1, mesh2);
        this.scene.add(this.quanGroup);
        this.time.on("tick", () => {
            mesh1.rotation.z += 0.05;
        });
        return this.quanGroup;
    }

    createGrid() {
        new Grid(this, {
            gridSize: 250,
            gridDivision: 100,
            gridColor: 0x1b4b70,
            shapeSize: 0.5,
            shapeColor: 0x2a5f8a,
            pointSize: 0.1,
            pointColor: 0x154d7d,
            diffuse: true,
            diffuseSpeed: 10.0,
            diffuseColor: 0x2e8bd9,
        });
    }

    createFloor() {
        let geometry = new PlaneGeometry(20, 20);
        const texture = this.assets.instance.getResource("ocean");
        texture.colorSpace = SRGBColorSpace;
        texture.wrapS = RepeatWrapping;
        texture.wrapT = RepeatWrapping;
        texture.repeat.set(1, 1);
        let material = new MeshBasicMaterial({
            map: texture,

            opacity: 1,
        });
        let mesh = new Mesh(geometry, material);
        mesh.rotateX(-Math.PI / 2);
        mesh.position.set(0, -0.7, 0);
        this.scene.add(mesh);
    }

    /**
     * 创建中国模糊边缘线
     */
    createChinaBlurLine() {
        let geometry = new PlaneGeometry(147, 147);
        const texture = this.assets.instance.getResource("chinaBlurLine");
        texture.colorSpace = SRGBColorSpace;
        texture.wrapS = RepeatWrapping;
        texture.wrapT = RepeatWrapping;

        texture.generateMipmaps = false;
        texture.minFilter = NearestFilter;
        texture.repeat.set(1, 1);
        let material = new MeshBasicMaterial({
            color: '#3f82cd',
            alphaMap: texture,
            transparent: true,
            opacity: 0.5,
        });
        let mesh = new Mesh(geometry, material);
        mesh.rotateX(-Math.PI / 2);
        mesh.position.set(0, 0, 0);
        mesh.uuid='base_china_line'
        this.scene.add(mesh);
    }

    createLabel() {
        let self = this;
        let labelGroup = this.labelGroup;
        let label3d = this.label3d;
        let otherLabel = [] as any;
        const _this = this;
        //显示区域标签
        StaticGroup.otherAreaInfo.map((province) => {
            if (province.hide != true) {
                let label = labelStyle01(province, label3d, labelGroup);
                otherLabel.push(label);
            }
        });

        // let gdLabel = labelStyle02(
        //     {
        //         name: StaticGroup.areaInfo.name,
        //         enName: "GUANGDONG PROVINCE",
        //         center: StaticGroup.areaInfo.center,
        //     },
        //     label3d,
        //     labelGroup
        // );
        //地区标签
        //otherLabel.push(gdLabel);
        this.otherLabel = otherLabel;

        function labelStyle01(province, label3d, labelGroup) {
            let label = label3d.create(
                "",
                `china-label ${province.blur ? " blur" : ""}`,
                true
            );
            const [x, y] = self.geoProjection(province.center);
            label.init(
                `<div class="other-label" style="display: ${StaticGroup.options.area_label_show?"block":"none"};background: ${StaticGroup.options.area_label_bg};${StaticGroup.options.area_label_pos.left}px ${StaticGroup.options.area_label_pos.top}px ${StaticGroup.options.area_label_pos.right}px ${StaticGroup.options.area_label_pos.bottom}px;color: ${StaticGroup.options.area_label_textStyle.color};font-family: '${StaticGroup.options.area_label_textStyle.fontFamily}';font-size: ${StaticGroup.options.area_label_textStyle.fontSize};font-style: ${StaticGroup.options.area_label_textStyle.fontStyle};font-weight: '${StaticGroup.options.area_label_textStyle.fontWeight}'">
                        ${province.name}</div>`,
                new Vector3(x, -y, StaticGroup.options.area_label_z*0.1)
            );
            label3d.setLabelStyle(label, 0.02, "x");
            label.setParent(labelGroup);
            return label;
        }

        function labelStyle02(province, label3d, labelGroup) {
            let label = label3d.create("", "areaInfo-label", true);
            const [x, y] = self.geoProjection(province.center);
            label.init(
                `<div class="other-label"><span>${province.name}</span><span>${province.name}</span></div>`,
                new Vector3(x, -y, 0.4)
            );
            label3d.setLabelStyle(label, 0.02, "x");
            label.setParent(labelGroup);
            return label;
        }
    }

    createRotateBorder() {
        let max = 12;
        let rotationBorder1 = this.assets.instance.getResource("rotationBorder1");
        let rotationBorder2 = this.assets.instance.getResource("rotationBorder2");
        let plane01 = new Plane(this, {
            width: max * 1.178,
            needRotate: true,
            rotateSpeed: 0.001,
            material: new MeshBasicMaterial({
                map: rotationBorder1,
                color: StaticGroup.options.base_plane_1,
                transparent: true,
                opacity: 0.2,
                side: DoubleSide,
                depthWrite: false,
                blending: AdditiveBlending,
            }),
            position: new Vector3(StaticGroup.areaConfig.rotpos.x, 0.28, StaticGroup.areaConfig.rotpos.z),
        });
        plane01.instance.renderOrder = 6;
        plane01.instance.scale.set(0, 0, 0);
        plane01.instance.uuid='base_plane_1';
        plane01.setParent(this.scene);
        //
        let plane02 = new Plane(this, {
            width: max * 1.116,
            needRotate: true,
            rotateSpeed: -0.004,
            material: new MeshBasicMaterial({
                map: rotationBorder2,
                color: StaticGroup.options.base_plane_2,
                transparent: true,
                opacity: 0.4,
                side: DoubleSide,
                depthWrite: false,
                blending: AdditiveBlending,
            }),
            position: new Vector3(StaticGroup.areaConfig.rotpos.x, 0.3, StaticGroup.areaConfig.rotpos.z),
        });
        plane02.instance.renderOrder = 6;
        plane02.instance.scale.set(0, 0, 0);
        plane02.instance.uuid='base_plane_2';
        plane02.setParent(this.scene);
        this.rotateBorder1 = plane01.instance;
        this.rotateBorder2 = plane02.instance;
    }

    // 创建飞线
    createFlyLine() {
        this.flyLineGroup = new Group();
        this.flyLineGroup.visible = false;
        this.scene.add(this.flyLineGroup);
        // 贴图
        const texture = this.assets.instance.getResource("flyLine");

        texture.wrapS = texture.wrapT = RepeatWrapping;
        texture.repeat.set(1, 1);
        const tubeRadius = 0.03;
        const tubeSegments = 32;
        const tubeRadialSegments = 8;
        const closed = false;
        let [centerX, centerY] = this.geoProjection(this.flyLineCenter);
        let centerPoint = new Vector3(centerX, -centerY, 0);
        const material = new MeshBasicMaterial({
            map: texture,
            alphaMap: texture,
            // 0x2a6f72  0x0d2025
            color: 0x2a6f72,
            transparent: true,
            fog: false,
            opacity: 1,
            depthTest: false,
            blending: AdditiveBlending,
        });
        this.time.on("tick", () => {
            texture.offset.x -= 0.006;
        });
        StaticGroup.bindPointData.filter((item, index) => index < 7)
            .map((city) => {
                let [x, y] = this.geoProjection(city.centroid);
                let point = new Vector3(x, -y, 0);
                const center = new Vector3();
                center.addVectors(centerPoint, point).multiplyScalar(0.5);
                // 设置曲线中间点的高度
                center.setZ(3);
                // 三维二次贝塞尔曲线
                const curve = new QuadraticBezierCurve3(centerPoint, center, point);
                // 管道几何体
                const tubeGeometry = new TubeGeometry(
                    curve,
                    tubeSegments,
                    tubeRadius,
                    tubeRadialSegments,
                    closed
                );
                const mesh = new Mesh(tubeGeometry, material);
                mesh.rotation.x = -Math.PI / 2;
                mesh.position.set(0, 0.94, 0);
                mesh.renderOrder = 21;
                this.flyLineGroup.add(mesh);
            });

        this.createFlyLineFocus();
    }

    createFlyLineFocus() {
        this.flyLineFocusGroup = new Group();
        this.flyLineFocusGroup.visible = false;
        this.flyLineFocusGroup.rotation.x = -Math.PI / 2;
        let [x, y] = this.geoProjection([113.544372, 23.329249]);
        this.flyLineFocusGroup.position.set(x, 0.942, y);
        this.scene.add(this.flyLineFocusGroup);
        const flyLineFocus = this.assets.instance.getResource("flyLineFocus");
        const geometry = new PlaneGeometry(1, 1);
        const material = new MeshBasicMaterial({
            color: 0xffffff,
            map: flyLineFocus,
            alphaMap: flyLineFocus,
            transparent: true,
            fog: false,
            depthTest: false,
            blending: AdditiveBlending,
        });
        const mesh = new Mesh(geometry, material);

        mesh.scale.set(0, 0, 0);
        const mesh2 = mesh.clone();
        mesh2.material = material.clone();
        this.flyLineFocusGroup.add(mesh, mesh2);
        gsap.to(mesh.material, {
            opacity: 0,
            repeat: -1,
            yoyo: false,
            duration: 1,
        });
        gsap.to(mesh.scale, {
            x: 1.5,
            y: 1.5,
            z: 1.5,
            repeat: -1,
            yoyo: false,
            duration: 1,
        });
        gsap.to(mesh2.material, {
            delay: 0.5,
            opacity: 0,
            repeat: -1,
            yoyo: false,
            duration: 1,
        });
        gsap.to(mesh2.scale, {
            delay: 0.5,
            x: 1.5,
            y: 1.5,
            z: 1.5,
            repeat: -1,
            yoyo: false,
            duration: 1,
        });
    }

    // 创建粒子
    createParticles() {
        this.particles = new Particles(this, {
            num: 10, // 粒子数量
            range: 30, // 范围
            dir: "up",
            speed: 0.05,
            material: new PointsMaterial({
                map: Particles.createTexture(),
                size: 1,
                color: 0x00eeee,
                transparent: true,
                opacity: 1,
                depthTest: false,
                depthWrite: false,
                vertexColors: true,
                blending: AdditiveBlending,
                sizeAttenuation: true,
            }),
        });
        this.particles.instance.position.set(0, 0, 0);
        this.particles.instance.rotation.x = -Math.PI / 2;
        this.particles.setParent(this.scene);
        // 停用,隐藏
        this.particles.enable = false;
        this.particles.instance.visible = false;
    }

    // 创建散点图
    createScatter() {
        this.scatterGroup = new Group();
        this.scatterGroup.visible = false;
        this.scatterGroup.rotation.x = -Math.PI / 2;
        this.scene.add(this.scatterGroup);
        // 贴图
        const texture = this.assets.instance.getResource("arrow");
        const material = new SpriteMaterial({
            map: texture,
            color: 0xfffef4,
            fog: false,
            transparent: true,
            depthTest: false,
        });

        let scatterAllData = sortByValue(scatterData);
        let max = scatterAllData[0].value;
        scatterAllData.map((data) => {
            const sprite = new Sprite(material);
            sprite.renderOrder = 23;
            let scale = 0.1 + (data.value / max) * 0.2;
            sprite.scale.set(scale, scale, scale);
            let [x, y] = this.geoProjection([data.lng, data.lat]);
            sprite.position.set(x, -y, this.depth + 0.45);
            sprite.userData.position = [x, -y, this.depth + 0.45];
            this.scatterGroup.add(sprite);
        });
    }

    // 创建信息点
    createInfoPoint() {
        let self = this;
        this.InfoPointGroup = new Group();
        this.InfoPointGroup.visible = false;
        this.InfoPointGroup.rotation.x = -Math.PI / 2;
        this.scene.add(this.InfoPointGroup);
        this.infoPointIndex = 0;
        this.infoPointLabelTime = null;
        this.infoLabelElement = [];
        let label3d = this.label3d;
        // 贴图
        const texture = this.assets.instance.getResource("point");
        let colors = [0xfffef4, 0x77fbf5];

        let infoAllData = sortByValue(infoData);
        let max = infoAllData[0].value;
        infoAllData.map((data, index) => {
            const material = new SpriteMaterial({
                map: texture,
                color: colors[index % colors.length],
                fog: false,
                transparent: true,
                depthTest: false,
            });
            const sprite = new Sprite(material);

            sprite.renderOrder = 23;
            let scale = 0.7 + (data.value / max) * 0.4;
            sprite.scale.set(scale, scale, scale);
            let [x, y] = this.geoProjection([data.lng, data.lat]);
            sprite.position.set(x, -y, this.depth + 0.7)
            sprite.userData.position = [x, -y, this.depth + 0.7];
            sprite.userData = {
                position: [x, -y, this.depth + 0.7],
                name: data.name,
                value: data.value,
                level: data.level,
                index: index,
            };
            this.InfoPointGroup.add(sprite);
            // 标签
            let label = infoLabel(data, label3d, this.InfoPointGroup);
            this.infoLabelElement.push(label);
            //const valu=this.formatData()
            // 事件
            this.interactionManager.add(sprite);
            sprite.addEventListener("mousedown", (ev) => {
                if (this.clicked) {
                } else {
                    //数据轮播
                    // this.clicked = true;
                    // this.infoPointIndex = ev.target.userData.index;
                    // this.infoLabelElement.map((label) => {
                    //     label.hide();
                    // });
                    // label.show();
                    // this.createInfoPointLabelLoop();
                }
            });
            sprite.addEventListener("mouseup", (ev) => {
                this.clicked = false;
            });
            sprite.addEventListener("mouseover", (event) => {
                document.body.style.cursor = "pointer";
            });
            sprite.addEventListener("mouseout", (event) => {
                document.body.style.cursor = "default";
            });
        });

        function infoLabel(data, label3d, labelGroup) {
            let label = label3d.create("", "info-point", true);
            const [x, y] = self.geoProjection([data.lng, data.lat]);
            label.init(
                ` <div class="info-point-wrap">
          <div class="info-point-wrap-inner">
            <div class="info-point-line">
              <div class="line"></div>
              <div class="line"></div>
              <div class="line"></div>
            </div>
            <div class="info-point-content">
              <div class="content-item"><span class="label">名称</span><span class="value">${data.name}</span></div>
              <div class="content-item"><span class="label">PM2.5</span><span class="value">${data.value}ug/m²</span></div>
              <div class="content-item"><span class="label">等级</span><span class="value">${data.level}</span></div>
            </div>
          </div>
        </div>
      `,
                new Vector3(x, -y, 2.4)
            );
            label3d.setLabelStyle(label, 0.015, "x");
            label.setParent(labelGroup);
            label.hide();
            return label;
        }
    }

    // 标签循环显示
    createInfoPointLabelLoop() {
        clearInterval(this.infoPointLabelTime);
        this.infoPointLabelTime = setInterval(() => {
            this.infoPointIndex++;
            if (this.infoPointIndex >= this.infoLabelElement.length) {
                this.infoPointIndex = 0;
            }
            this.infoLabelElement.map((label, i) => {
                if (this.infoPointIndex === i) {
                    label.show();
                } else {
                    label.hide();
                }
            });
        }, 3000);
    }


    /**
     * 清空地图
     */
    clearMap() {
        //删除地图
        if (this.mapGroup) {
            gsap.to(this.focusMapGroup, {
                duration: 0.1,
                visible: false,
                ease: "circ.out",
            }).then(() => {
                this.mapGroup.remove(this.focusMapGroup);
                this.focusMapGroup = null;
            });
            gsap.to(this.rotateBorder2, {
                duration: 0.1,
                visible: false,
                ease: "circ.out",
            }).then(() => {
                this.scene.remove(this.rotateBorder2);
                this.rotateBorder2 = null;
            });
            gsap.to(this.rotateBorder1, {
                duration: 0.1,
                delay: 0.1,
                visible: false,
                ease: "circ.out",
            }).then(() => {
                this.scene.remove(this.rotateBorder1);
                this.rotateBorder1 = null;
            });

        }
        //删除柱子
        if (this.barGroup) {
            this.allBar.map((item, index) => {
                gsap.to(item, {
                    duration: 0.1,
                    delay: 0.1,
                    visible: false,
                    ease: "circ.out",
                });
            });
            this.allBarMaterial.map((item, index) => {
                gsap.to(item, {
                    duration: 0.1,
                    opacity: 0,
                    ease: "circ.out",
                })
            });

            setTimeout(() => {
                this.scene.remove(this.barGroup);
                this.barGroup = null;
                this.allBar = null;
            }, 200)
        }
        //删除光圈
        if (this.quanGroup) {
            //底部光圈
            this.allGuangquan.map((item, index) => {

                gsap.to(item.children[0], {
                    duration: 0.1,
                    delay: 0.1,
                    visible: false,
                    ease: "circ.out",
                })
                gsap.to(item.children[1], {
                    duration: 0.1,
                    delay: 0.1,
                    visible: false,
                    ease: "circ.out",
                })
            });
            setTimeout(() => {
                this.scene.remove(this.quanGroup);
                this.quanGroup = null;
                this.allGuangquan = null;
            }, 200)
        }
        //删除其他标签
        if (this.labelGroup) {
            this.otherLabel.map((item, index) => {
                let element = item.element.querySelector(".other-label");
                gsap.to(element, {
                    duration: 0.1,
                    delay: 0.1,
                    opacity: 0,
                    ease: "circ.out",
                })
            });
            this.scene.remove(this.labelGroup);
        }
        //柱子标签
        this.allProvinceLabel.map((item, index) => {
            let element = item.element.querySelector(".provinces-label-wrap");
            let number = item.element.querySelector(".number .value");
            gsap.to(element, {
                duration: 0.1,
                delay: 0.1,
                opacity: 0,
                ease: "circ.out",
            })
            gsap.to(number, {
                duration: 1,
                delay: 0.1,
                opacity: 0,
                ease: "circ.out",
            })
        });
        //删除散点
        if (this.scatterGroup) {
            gsap.to(this.scatterGroup, {
                duration: 0.1,
                delay: 0.1,
                visible: false,
                ease: "circ.out",
            }).then(() => {
                this.scene.remove(this.scatterGroup);
                this.scatterGroup = null;
            });
        }
        // //删除轮播标签
        if (this.infoLabelElement) {
            clearInterval(this.infoPointLabelTime);
            this.infoLabelElement.map((label, i) => {
                label.hide();
            });
        }
        this.interactionManager.dispose();

        this.scene.remove.apply(this.scene, this.scene.children);
        this.scene.clear();
    }

    // 转换坐标
    geoProjection(args) {
        return geoMercator().center(this.pointCenter).scale(StaticGroup.areaConfig.scale).translate([0, 0])(
            args
        );
    }

    // 更新
    update() {
        super.update({});
        this.interactionManager && this.interactionManager.update();
    }

    // 销毁
    destroy() {
        super.destroy();
        this.label3d && this.label3d.destroy();
    }

    //------------数据联动 star--------------
    public onCustomEventHandler = (name: string) => {

    }


    public getNodeSelectionId = (label: any) => {
        if (StaticGroup.items.find((item: any) => item.name === label)){
            const {selectionId} = StaticGroup.items.find((item: any) => item.name === label);
            return selectionId
        }else{
            return null;
        }
    }
    private clickHandler = (node: any) => {
        if (StaticGroup.items.length == 0) {
            return;
        }
        const selectionId = this.getNodeSelectionId(node);
        if (selectionId) {
            if (!StaticGroup.selectionManager.contains(selectionId)) {
                StaticGroup.selectionManager.select(selectionId, true);
            } else {
                StaticGroup.selectionManager.clear(selectionId);
            }
        }
    }

    //---------数据联动 end --------------------

    public setAttributeSetting() {
        new MapSetting(this.scene,this.allProvinceLabel,this.otherLabel).initSetting()
    }
    public divresize(){
        this.resize();
        this.sizes.init();
        this.sizes.emit("resize");
    }

}
